package uk.ac.aber.paws.client.core;

import java.util.Calendar;
import java.util.logging.Level;
import uk.ac.aber.paws.client.db.DBOperations;
import uk.ac.aber.paws.client.power.*;
import uk.ac.aber.paws.client.state.LoginProcessOperations;
import uk.ac.aber.paws.client.updater.UpdateManager;
import uk.ac.aber.paws.client.util.*;
import uk.ac.aber.paws.client.net.*;
import static uk.ac.aber.paws.client.constants.Constants.*;

/**
 * @author Rob Johnson, Aberystwyth University
 * @email rob.johnson@aber.ac.uk
 * @date 16th August 2011
 * 
 * RunJob.java
 * 
 * This is a thread class that will spawn the required new processes.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

public class RunJob extends Thread {
		
	private int id;
	private int time;
	private boolean running = true;
	
	public RunJob(int id, int time) {
		
		this.id = id;
		
		// convert into milliseconds
		this.time = time * 1000;
	
		this.start();
	}
	
	public RunJob(int id) {
		
		this.id = id;
		
		// not required
		this.time = -1;
	
		this.start();
	}

	public void run() {
				
		Initiator.LOG_FILE.log(Level.CONFIG,"Starting Thread # "+id);
		
		try {
	
			if (id == RUNJOB_HEALTH_CHECK) {
				
				long startTime = Calendar.getInstance().getTimeInMillis() + (60*1000);
				
				while (running) {
					
					try {
						if (PAWSClient.getThreads() != null) {
							PAWSClient.getThreads().checkThreadHealth(startTime);
						}
						else {
							// restart the service
							Operations.cleanCloseDown(true);
						}
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+ex.toString());
						ex.printStackTrace();
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
				
			}
			// Monitor user logins on this computer.
			// This will repeatedly call qwinsta and retrieve a list of logged in users and log
			// this data to the database
			else if (id == RUNJOB_MONITOR_USER_LOGINS) {
	
				Initiator.LOG_FILE.log(Level.CONFIG,"Start of Login Monitoring Thread.");
				
				// sets the maximum processor priority for this thread so will hopefully be consistently run on time
				//this.setPriority(MAX_PRIORITY);
				
				Initiator.LOG_FILE.log(Level.CONFIG,"Thread set to priority level: "+this.getPriority());
				
				// check if a stale logout entry for this computer, if so, set valid time. A stale
				// entry may have occurred by a user not logging out previously
				LoginProcessOperations.runPreCheck();
				
				Initiator.LOG_FILE.log(Level.CONFIG,"Login Monitoring pre check has been run");
				
				Initiator.LOG_FILE.log(Level.CONFIG,"Starting Process Login process.");
				
				while (running) {
					
					Initiator.LOG_FILE.log(Level.CONFIG,"Running processLogin procedure...");
					
					try {
						// check the current user logins for this computer
						LoginProcessOperations.processLogin();
						
						this.yield();
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
				
				Initiator.LOG_FILE.log(Level.CONFIG,"Ending Process Login process.");
			}
			
			// Looks at previously cached DB calls in the flat files present in the cache/ folder and
			// processes them into the database. Cached DB calls may be present due to previous database
			// server unavailability. This is a one off call at the start of the application
			else if (id == RUNJOB_PARSE_SAVED_DB_CONNECTIONS) {
				
				DBOperations.repopulateSavedDBCalls();
				
				this.yield();
			}
			
			// Loops through parsing queued database calls
			else if (id == RUNJOB_PARSE_QUEUED_CONNECTIONS) {
				
				while (running) {
					
					try {
						DBOperations.parseQueuedDBCalls();
						
						this.yield();
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
				
			}
		
			// start a server socket to listen for server actioned sleep requests to sleep this computer
			else if (id == RUNJOB_START_SERVERSOCKET_LISTENER) {
				
				// run once to setup the Server Socket
				new ServerSocketListener(true);
				
			}
			
			// start input simulator - not sure if required now?
			else if (id == RUNJOB_START_INPUT_SIMULATOR) {
				
				while (running) {
					
					try {
						// simulates a click, this might be useful to stop a sleep from occurring
						ClickSimulator.simulateInput();
						
						this.yield();
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
				
			}
			// start a process that detects when the computer has woke up and logs to database
			else if (id == RUNJOB_START_WAKE_DETECTOR) {
				
				//this.setPriority(MAX_PRIORITY);
				
				while (running) {
					
					try {
						WakeDetector.register(10l);
						
						this.yield();
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
			}
			// checks the server for any new updates of this software
			else if (id == RUNJOB_CHECK_FOR_UPDATE) {
				
				while (running) {
					
					try {
						UpdateManager.checkForJarUpdate();
						
						this.yield();
					}
					catch (Exception ex) {
						Initiator.LOG_FILE.log(Level.CONFIG,"Problems with Thread: "+id);
					}
					
					sleep(time);
				}
			}
			
			Initiator.LOG_FILE.log(Level.ALL,"***************WARNING: Stopped running Thread "+id);
			
		}
		catch (InterruptedException ex) {
			Initiator.LOG_FILE.log(Level.ALL,"***************WARNING: Stopped running Thread "+id+" "+ex.toString());
		}
		catch (Exception ex) {
			Initiator.LOG_FILE.log(Level.ALL,"***************WARNING: Stopped running Thread "+id+" "+ex.toString());
		}
	}
	
	public void killMe() {
	
		running = false;	
	}	
}
